package com.example.helloworld;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring Factories机制
 * 	Spring Boot自动配置机制是通过Spring Factories机制实现的
 * 	Spring Factories是一种服务发现机制，扫描所有jar包类路径下 META-INF/spring.factories 文件，读取其中的内容，并实例化。这也是Spring Boor Starter的基础
 * 		spring.factories文件类似于properties文件，包含一组或多组键值对，其中 key 为接口的完全限定名， values 为接口实现类的完全限定名，多个实现类之间用逗号隔开
 * Spring Factories实现原理
 * 	spring-core 包含定义了 SpringFactoriesLoader 实现类，该类会扫描所有jar包下 META-INF/spring.factories 文件，并获取接口的指定配置
 * 			其中方法 <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader)获取所有实现类的实例
 * 		方法 List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) 获取所有实现类完全限定名
 * 自动配置的加载
 * 	Spring Boot 的自动配置也是通过 String Factories 机制实现的，在 spring-boot-autoconfigure-xxx.jar包的类路径下的 META-INF/spring.factories 文件设置了 Spring Boot 自动配置的相关内容
 * 	Spring Boot 启动时会利用 Spring Factories 机制将 Spring Boot 的自动配置相关内容 xxxAutoConfiguration 进行实例化并作为组件加入到容器中
 * @SpringBootApplication 注解 -- 一切组件加载的起始
 * 	@SpringBootApplication 是一个组合元注解，主要包含两个注解： @SpringBootConfiguration 和 @EnableAutoConfiguration ，其中注解 @EnableAutoConfiguration 又是 SpringBoot 自动配置的核心
 *  	@EnableAutoConfiguration 注解用于开启 Spring Boot 的自动配置功能，其使用 Spring 框架提供的 @Import注解通过 AutoConfigurationImportSelector 类给容器导入自动配置组件
 * AutoConfigurationImportSelector类
 * 	AutoConfigurationImportSelector 类实现了 DeferredImportSelector 接口，并包含一个静态内部类 AutoConfigurationGroup，实现了接口 DeferrdImportSelector 接口的内部接口 Group，该类还包含以下3个方法：
 * 		Class<? extends Group> getImportGroup()   --- 用于获取实现了DeferrdImportSelector。Group 接口的类
 * 		void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector)    --- 读取Spring.factories文件中的内容获得自动配置的集合，存到成员变量中
 * 		Iterable<Entry> selectImports()    --- 将process()方法得到的自动配置类，进行过滤、排除，最后将所有自动配置类添加到容器中
 *
 * 自动配置的生成和修改
 *  @ConditionOnJava			--- 使用指定Java版本时生效
 *  @ConditionOnBean			--- 容器中存在指定Bean时生效
 *  @ConditionOnMissingBean		--- 容器中不存在指定的Bean时生效
 *  @ConditionOnExpression		--- 满足指定的SpEL表达式时生效
 *  @ConditionOnClass			--- 存在指定的类时生效
 *  @ConditionOnMissingClass	--- 不存在指定的类时生效
 *  @ConditionOnSingleCandidate	--- 容器中只存在一个指定的Bean或者这个Bean为首选Bean时生效
 *  @ConditionOnProperty		--- 系统中指定属性存在指定的值时生效
 *  @ConditionOnResource		--- 类路径下存在指定的资源文件时生效
 *  @ConditionOnWebApplication	--- 当前应用是Web应用时生效
 *  @ConditionOnNotWebApplication - 当前应用不是Web应用时生效
 */
@SpringBootApplication
public class HelloworldApplication {

	public static void main(String[] args) {
		SpringApplication.run(HelloworldApplication.class, args);
	}

}
